package TreeMap;

import sun.security.timestamp.TSRequest;

import java.security.KeyStore;
import java.util.*;
import java.util.TreeMap;

class Student {
    private String id;

    public Student() {

    }
    public Student(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id);
    }

    @Override
    public int hashCode() {
        //他是根据object中的hash以id的方式生成的一个哈希码，此时就一样了
        return Objects.hash(id);
    }
}
public class Text {
    public static void main15(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(12);
        set.add(133);
        set.add(12222);
        int val = set.hashCode();
        System.out.println(val);
    }
    public static void main14(String[] args) {//14
        char[] ch = new char[]{'a','b','c'};
        String s1 = new String(ch);
        s1.intern();//true  手动入常量池：把s1所指向的对象放到常量池
        String s2 = "abc";//这个时候再看常量池中有没有这个abc，有了就直接指向它的地址
        System.out.println(s1 == s2);//false

        /*String s1 = "hello";
        String s2 = "hello";
        String s3 = new String("world");
        String s4 = new String("world");
        System.out.println(s1 == s2);//true
        System.out.println(s3 == s4);//false
        System.out.println(s1 == s3);//false*/
    }

    public static void main13(String[] args) {

    }
    //只出现依1次的数字---用Set/Map实现
    /*所有的数据都是出现两次的，只有一个元素是出现一次的*/
    public static int singleNumber2(int[] nums) {
        //用Map是存放着key值对应的value的，所以遍历数组，如果没有就把数组放进来，把value值设置为1，
        //如果已经有这个数据了，就把这个数据的value值在原来的基础上+1；最后输出value=1的key值
        Map<Integer,Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (!map.containsKey(nums[i])) {
                map.put(nums[i],1);//没有就把数据放进来，然后val设为1
            }else {
                int val = map.get(nums[i]);
                map.put(nums[i],val+1);//如果有就在原来的基础上val+1；
            }
        }
        //遍历map然后输出val=1的数据
        /*Entry这个方法：就是说如果我想通过这个key的值来看一下value值，就可以拿这个方法实现*/
        for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
            if (entry.getValue() == 1) {//如果重复的值的次数>1才输出它
                return entry.getKey();
            }
        }
        return -1;
    }
    public static int singleNumber1(int[] nums) {
        //用Set，先遍历这个数组，如果没有这个元素，就放进来，如果没有就把这个元素删除
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            if (!set.contains(nums[i])) {
                set.add(nums[i]);
            }else {
                set.remove(nums[i]);
            }
        }
        int val = set.hashCode();//为什么hashcode方法也是可以输出set中只有一个数据的情况
        return val;
    }

    public static void func2(String s1) {
        Set<Character> set = new HashSet<>();
        for (char ch : s1.toUpperCase().toCharArray()) {//把这个str2变成大写然后变成一个数组
            set.add(ch);//每一个ch就是一个大写的字符
        }
        System.out.println(set);
    }

    public static void main(String[] args) {
        String s1 = "aabbggdcccc";
        func2(s1);

    }
    //坏 键 盘  打  字
    public static void func(String str1,String str2) {
        Set<Character> set = new HashSet<>();
        for (char ch : str2.toUpperCase().toCharArray()) {//把这个str2变成大写然后变成一个数组
            set.add(ch);//每一个ch就是一个大写的字符
        }
        System.out.println(set);
        Set<Character> setBroken = new HashSet<>();
        for (char ch1 : str1.toUpperCase().toCharArray()) {//把这个str2变成大写然后变成一个数组
            if (!set.contains(ch1) && !setBroken.contains(ch1)) {
                setBroken.add(ch1);
                System.out.print(ch1);
            }
        }
    }
    public static void main11(String[] args) {
        Scanner scan = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (scan.hasNextLine()) {
            String str1 = scan.nextLine();
            String str2 = scan.nextLine();
            func(str1,str2);
        }
    }
    public static void main10(String[] args) {
        int[] array = {1,2,2,3,3,5,5,66,1};
        //int ret = singleNumber1(array);
        int ret = singleNumber2(array);
        System.out.println(ret);
    }
    public static void main9(String[] args) {
        //统计数组中 重复数据（val>=2）出现的次数？
        //key是数组中的数据，value是key这个数据在数组中出现了几次
        /*首先要清楚用哪一个容器来存储，Set容器只是存放了key值，Map容器存放了key值和value值
        * 所以用Map容器*/
        int[] array = {1,3,5,7,4,4,5,5,5,1};
        Map<Integer,Integer> map = new HashMap<>();
        for (int x : array) {//遍历数组
            if (map.get(x) == null) {
                //如果map这个容器中没有存放这个数据，就将value值设置为1
                map.put(x,1);
            }else {  //如果有，就在原来的value值的基础上+1
                //所以先看一下原来的这个value值是几，在原来的value值的基础上+1
                int val = map.get(x);
                map.put(x,val+1);
            }
        }
        for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
            if (entry.getValue() > 1) {//如果重复的值的次数>1才输出它
                System.out.println("key"+entry.getKey()+" value: "+entry.getValue());
            }
        }

        //或者是用Map中的map.getOrDefault()方法
        for (int x : array) {//默认值是0，在原来的基础上去更新+1
            map.put(x,map.getOrDefault(x,0)+1);
        }
    }
    public static void main8(String[] args) {
        //找到第一个重复的数据   最好用接口引用一个类！！！
        //因为它包含接口的方法，如果用一个集合类去引用只能使用当前类的方法
        int[] array = {1,3,4,5,3,5,1,2,8};
        Set<Integer> set = new HashSet<>();
        for (int x : array) {
            if (!set.contains(x)) {
                set.add(x);
            }else {
                System.out.println(x);
                return;
            }
        }
    }
    public static void main7(String[] args) {
        //给数据去重
        int[] array = {1,3,4,5,3,5,1,2,8};
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < array.length; i++) {
            set.add(array[i]);
        }
        System.out.println(set);
     }
    public static void main6(String[] args) {
        HashBuck2<Student,String> hashBuck2 = new HashBuck2<Student, String>();
        Student student1 = new Student("123");
        System.out.println(student1.hashCode());

        Student student2 = new Student("123");
        System.out.println(student2.hashCode());
        //我放进去一个对象1，然后我用对象2去取出，因为这两个引用的hash值是一样的
        hashBuck2.put(student1,"jiaoao");
        String str = hashBuck2.get(student1);
        System.out.println(str);
    }
    public static void main5(String[] args) {
        //刚才的key是一个int类型的，是一个正数，如果是一个引用类型作为key要把它变成一个正数
        //就用hashcode()方法，但是这个和对象的比较是一样的，这是两个不同的对象，虽然id是一样的
        //如果我们认为id一样就是一个人的，他们生成的哈希码也应该是一样的，就需要重写hashcode方法
        Student student1 = new Student("123");
        System.out.println(student1.hashCode());

        Student student2 = new Student("123");
        System.out.println(student2.hashCode());
    }
    //面试题：
    //int a = 'a';  字符a所对应的阿斯克码值是97
    //给一个字符串然后返回它的第一个不重复的字符，并返回它的索引，不存在返回-1
    public int firstUniqChar(String s) {
        if (s == null) {
            return -1;
        }
        int[] str = new int[26];
        int len = s.length();
        for (int i = 0; i < len; i++) {
            str[s.charAt(i)-'a']++;//每拿到一个字符就让数组对应的下标值+1
        }
        for (int i = 0; i < len; i++) {
            if (str[s.charAt(i)-'a'] == 1) {
                return i;
            }
        }
        return -1;
    }

    public static void main4(String[] args) {
        HashBuck hashBuck = new HashBuck();
        hashBuck.put(1,23);
        hashBuck.put(2,34);
        hashBuck.put(14,45);
        hashBuck.put(6,56);
        hashBuck.put(21,333);
        hashBuck.put(5,67);
        hashBuck.put(7,78);
        hashBuck.put(3,89);
        hashBuck.put(8,99);
        Integer val = hashBuck.get(6);
        System.out.println(val);
    }
    public static void main3(String[] args) {
        Set<String> set = new TreeSet<>();
    }
    public static void main2(String[] args) {
        Map<Student,Integer> treeMap = new TreeMap<>();
        //会报错，类型转换异常，说明key的值一定是可以比较的，但是在STudent类中没有可以进行比较的值
        treeMap.put(new Student(),1);
        treeMap.put(new Student(),4);
        System.out.println(treeMap);
    }
    public static void main1(String[] args) {
        /*Map是一个接口，用接口的引用创建一个对象，treeMap底层是一个搜索树
        * */
        Map<String,Integer> treeMap= new TreeMap<>();
        treeMap.put("hello",3);//往里边存放数据，Key-value的形式存储
        treeMap.put("the",8);//比较的时候是用key去比较的
        treeMap.put("abc",4);
        System.out.println(treeMap);//重写了toString方法
        Integer val = treeMap.get("abc");//给一个key值，返回相对应的val值
        //如果treeMap中没有这个val值，就是null
        //还有就是如果没有这个key值可以给定一个默认值
        Integer val1 = treeMap.getOrDefault("hello44",100);
        System.out.println(val1);
        //keySet方法可以将treeMapp中存放的值进行输出，但是没有顺序，是乱序存放的
        Set<String> keySet = treeMap.keySet();
        System.out.println(keySet);
        /*Map.Entry<String,Integer>  他是一个类似节点这样的类型，就像是node，Entry是
        * 一个接口，它的里面也有方法，map也是一个接口，有点类似外部类.内部类这样，entrySet
        * 这个方法可以将里面存放的key值和value值放进另一个麻袋中，然后可以遍历这个麻袋进行
        * 输出拿到key值和value值，是Map中一个用来存放键值对的映射关系的一个内部类*/
        Set<Map.Entry<String,Integer>> set = treeMap.entrySet();
        for (Map.Entry<String,Integer> entry : set) {
            System.out.println("key: "+entry.getKey() + " value: "+entry.getValue());
        }
    }
}
